
local require = require
local setmetatable = setmetatable
local error = error
local table = table
local ngx = ngx
local os = os
local string = string
local tostring = tostring 
local tonumber = tonumber
local server = require "modules.server"
local redis = require "redis"
local json = require 'cjson'
local util = require 'util'
local protocal = require 'protocal'
package.cpath = "/opt/xyitech/jieyan-backend-production/xbit/?.so"
local xbit = require 'xbit'
ngx.log(ngx.ERR, "xbit after")
module(...)
_VERSION = '0.1'
 _int32_t = 0
 _int16_t = 1
 _float = 2
 _uint32_t = 4
 _uint16_t = 5
 _uint8_t = 6
 _int8_t = 7
local main_channel_name = "jieyan"

function create()
    -- body

    --create connection
    local wb, err = server:new{
      timeout = 5000,
      max_payload_len = 65535
    }
    ngx.log(ngx.ERR, "websocket connected")
    -- local uid = util.get_uid()
    -- local my_fid = nil
    -- local moniter_fid = nil
    --create success
    if not wb then
      ngx.log(ngx.ERR, "failed to new websocket: ", err)
      return ngx.exit(444)
    end
     
    local push = function()
        -- --create redis
        local red = redis:new()
        -- red:set_timeout(1000) -- 1 sec
        local ok, err = red:connect("127.0.0.1", 6379)
        if not ok then
            ngx.log(ngx.ERR, "failed to connect redis: ", err)
            wb:send_close()
            return
        end
        -- --sub
        -- local res, err = red:subscribe(main_channel_name)
        -- if not res then
        --     ngx.log(ngx.ERR, "failed to sub redis: ", err)
        --     wb:send_close()
        --     return
        -- end
        
        -- local res, err = red:subscribe("ws_" .. uid)
        -- if not res then
        --     ngx.log(ngx.ERR, "failed to sub redis: ", err)
        --     wb:send_close()
        --     return
        -- end

        -- local res, err = red:subscribe("fs_all")
        -- if not res then
        --     ngx.log(ngx.ERR, "failed to sub redis: ", err)
        --     wb:send_close()
        --     return
        -- end

        local res, err = red:subscribe("ws_update")
        if not res then
            ngx.log(ngx.ERR, "failed to sub redis: ", err)
            wb:send_close()
            return
        end
        -- loop : read from redis
        while true do
            local res, err = red:read_reply()
            if res then
                local data = res[3]
                -- TODO transfer buffer data to json
                
                if not wb then
                    ngx.log(ngx.ERR, "lost websocket: ")
                    return ngx.exit(444)
                end

                data = filterMapData(data)
                if data then
                    local bytes, err = wb:send_text(data)
                    if not bytes then
                        -- better error handling
                        ngx.log(ngx.ERR, "failed to send text: ", err)
                        return ngx.exit(444)
                    end
                end
            else
                if err ~= "timeout" then
                    ngx.log(ngx.ERR, "Redis read error: ", err)
                    return ngx.exit(444)
                end
            end
        end
    end
     
    local red_p = redis:new()
    red_p:set_timeout(1000) -- 1 sec
    local ok, err = red_p:connect("127.0.0.1", 6379)
    if not ok then
        ngx.log(ngx.ERR, "failed to connect redis: ", err)
    end
    local co = ngx.thread.spawn(push)
    local red2 = redis:new()
    -- red2:set_timeout(1000) -- 1 sec
    local ok, err = red2:connect("127.0.0.1", 6379)
    if not ok then
        ngx.log(ngx.ERR, "failed to connect redis: ", err)
    end
    --main loop
    while true do
        -- 获取数据
        local data, typ, err = wb:recv_frame()

        -- 如果连接损坏 退出
        if wb.fatal then
            ngx.log(ngx.ERR, "failed to receive frame: ", err)
            return ngx.exit(444)
        end
     
        if not data then
            local bytes, err = wb:send_ping()
            if not bytes then
              ngx.log(ngx.ERR, "failed to send ping: ", err)
              return ngx.exit(444)
            end
            -- ngx.log(ngx.ERR, "send ping: ", data)
        elseif typ == "close" then
            ngx.log(ngx.ERR, "close")
            break
        elseif typ == "ping" then
            local bytes, err = wb:send_pong()
            if not bytes then
                ngx.log(ngx.ERR, "failed to send pong: ", err)
                return ngx.exit(444)
            end
        elseif typ == "pong" then
            -- ngx.log(ngx.ERR, "client ponged")
        elseif typ == "text" or typ == "binary" then
            --send to redis
            ngx.log(ngx.ERR, data)
            local res, err = red_p:publish("fs_update", data)
            if not res then
                ngx.log(ngx.ERR, "failed to publish redis: ", err)
            end
        end
    end
    ngx.log(ngx.ERR, "websocket closing")
    wb:send_close()
    ngx.thread.wait(co)
end

function filterMapData(data)
    return data
end
--  _int32_t = 0
--  _int16_t = 1
--  _float = 2
--  _uint32_t = 4
--  _uint16_t = 5
--  _uint8_t = 6
--  _int8_t = 7

function default(args)
    if args.action == 'create' then
        create(args)
    end
end
local class_mt = {
    __newindex = function (table, key, val)
        error('attempt to write to undeclared variable "' .. key .. '"')
    end
}
setmetatable(_M, class_mt)